package com.flexcloudsdk.web;

import java.io.IOException;

import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.flexcloudsdk.users.CloudUser;

public class CloudUsersServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
	private static final Logger log = Logger.getLogger(CloudUsersServlet.class
			.getName());
	private CloudUser user = new CloudUser();
	private String sourceClass;
	private String sourceMethod;
	public CloudUsersServlet() {
		super();
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		sourceClass = CloudUsersServlet.class.getName();
		log.info("*****CloudUsersServlet constructor********");
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		sourceClass = CloudUsersServlet.class.getName();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

	/*
		userId = UserServiceFactory.getUserService().getCurrentUser()
				.getUserId();
		ChannelService channelService = ChannelServiceFactory
				.getChannelService();
		String token = channelService.createChannel(userId);
*/
		
		resp.setContentType("text/html");
	//	resp.getWriter().write(token);
	}

	// I am highly aware that sending uint instead of strings for
	// method calls would be faster but better to get the logic working'
	// and then optimize these if statements into a switch statement
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		resp.setContentType("text/xml");
		PrintWriter writer = resp.getWriter();
		writer.println("<?xml version=\"1.0\"?>");
		writer.println("<root>");

		String operation = req.getParameter("operation");
		// handle the error condition
		if (operation == null) {
			handleNullOperation(writer, req);
		} else if (operation.isEmpty()) {
			handleEmptyOperation(writer, req);
		} else {
			CloudMethods enumval = CloudMethods.valueOf(operation);
			switch (enumval) {
			case compareToMethod:
				compareTo(writer);
				break;
			case createLoginURLMethod:
				createLoginURL(user, writer, req, resp);
				break;
			case createLogoutURLMethod:
				createLogoutURL(user, writer, req, resp);
				break;
			case createNewUserMethod:
				createNewUser(user, writer, req, resp);
				break;
			case getAuthDomainMethod:
				getAuthDomain(user, writer, req, resp);
				break;
			case getCurrentUserMethod:
				getCurrentUser(user, writer, req, resp);
				break;
			case getEmailMethod:
				getEmail(user, writer, req, resp);
				break;
			case getFederatedIdentityMethod:
				getFederatedIdentity(user, writer, resp);
				break;
			case getNicknameMethod:
				getNickname(writer, resp);
				break;
			case getUserIdMethod:
				getUserId(writer, resp);
				break;
			case isUserAdminMethod:
				isUserAdmin(writer);
				break;
			case isUserLoggedInMethod:
				isUserLoggedIn(writer);
				break;
			default:
				log.severe("Uknown method did the sdk get updated?");
				break;
			}
		}
		writer.println("</root>");
	}

	private void getUserId(PrintWriter writer, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		String userId = user.getUserId();
		if (userId != null && userId.isEmpty() == false) {
			writer.println("<result>" + userId + "</result>");
		} else {
			try {
				resp.sendError(400, "getUserId call failed");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void isUserLoggedIn(PrintWriter writer) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		Boolean flag = user.isUserLoggedIn();
		writer.println("<result>" + flag + "</result>");
	}

	private void isUserAdmin(PrintWriter writer) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		Boolean flag = user.isUserAdmin();
		writer.println("<result>" + flag + "</result>");
	}

	private void createLogoutURL(CloudUser user, PrintWriter writer,
			HttpServletRequest req, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		String[] parms = req.getParameterValues(createLogoutURLCall);
		String destinationURL = "";
		if (parms != null)
			destinationURL = parms[0];

		String resultValue;
		switch (parms.length) {
		case 1: {
			log.info("with 1 parms");
			resultValue = user.createLogoutURL(destinationURL);
			if (resultValue != null && resultValue.isEmpty() == false) {
				writer.println("<result>" + resultValue + "</result>");
			} else {
				try {
					resp.sendError(400,
							"createLogoutURL call failed with parms: "
									+ destinationURL);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
			break;
		case 2: {
			log.info("with 2 parms");
			String authDomain = parms[1];
			resultValue = user.createLogoutURL(destinationURL, authDomain);
			if (resultValue != null && resultValue.isEmpty() == false) {
				writer.println("<result>" + resultValue + "</result>");
			} else {
				try {
					resp.sendError(400,
							"createLogoutURL call failed with parms: "
									+ destinationURL + "," + authDomain);
				} catch (IOException e) {
					e.printStackTrace();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
			break;
		default:
			log.severe(createLogoutURLCall
					+ " needs to be calle with 1,2 parms and was not!");
			break;
		}
	}

	private void createLoginURL(CloudUser user, PrintWriter writer,
			HttpServletRequest req, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		String[] parms = req.getParameterValues(createLoginURLCall);
		String resultValue;
		if (parms == null)
			return;
		switch (parms.length) {
		case 1: {
			log.info("with 1 parms");
			String destinationURL = parms[0];
			resultValue = user.createLoginURL(destinationURL);
			if (resultValue != null && resultValue.isEmpty() == false) {
				writer.println("<result>" + resultValue + "</result>");
			} else {
				try {
					resp.sendError(400,
							"createLoginURL call failed with parms: "
									+ destinationURL);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
			break;
		case 2: {
			log.info("with 2 parms");
			String destinationURL = parms[0];
			String authDomain = parms[1];
			resultValue = user.createLoginURL(destinationURL, authDomain);
			if (resultValue != null && resultValue.isEmpty() == false) {
				writer.println("<result>" + resultValue + "</result>");
			} else {
				try {
					resp.sendError(400,
							"createLoginURL call failed with parms: "
									+ destinationURL + "," + authDomain);
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
			break;
		case 4: {
			log.info("with 4 parms");
			String destinationURL = parms[0];
			String authDomain = parms[1];
			String federatedIdentity = parms[2];
			Set<String> attributesRequest = new HashSet<String>();
			attributesRequest.add(parms[3]);

			resultValue = user.createLoginURL(destinationURL, authDomain,
					federatedIdentity, attributesRequest);
			if (resultValue != null && resultValue.isEmpty() == false) {
				writer.println("<result>" + resultValue + "</result>");
			} else {
				try {
					resp.sendError(400,
							"createLoginURL call failed with parms: "
									+ destinationURL + "," + authDomain + ","
									+ federatedIdentity + ","
									+ attributesRequest.toString());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
			break;
		default:
			log.severe(createLoginURLCall
					+ " needs to be called with 1,2,4 parms and was not");
			break;
		}
	}

	private void getNickname(PrintWriter writer, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		String nckName = user.getNickname();
		if (nckName != null && nckName.isEmpty() == false) {
			writer.println("<result>" + nckName + "</result>");
		} else {
			try {
				resp.sendError(500, "getNickname call failed");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void getFederatedIdentity(CloudUser user2, PrintWriter writer,
			HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		String federatedIdentity = user.getFederatedIdentity();
		if (federatedIdentity != null && federatedIdentity.isEmpty() == false) {
			writer.println("<result>" + federatedIdentity + "</result>");
		} else {
			try {
				resp.sendError(500, "getFederatedIdentity call failed");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void getEmail(CloudUser user2, PrintWriter writer,
			HttpServletRequest req, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		String email = user.getEmail();
		if (email != null && email.isEmpty() == false) {
			writer.println("<result>" + user.getEmail() + "</result>");
		} else {
			try {
				resp.sendError(400, "getEmail call failed");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void getCurrentUser(CloudUser user, PrintWriter writer,
			HttpServletRequest req, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		
		user = user.getCurrentUser();
		if (user != null) {
			writer.println("<result>" + user.getAuthDomain() + "</result>");
			writer.println("<result>" + user.getEmail() + "</result>");
			writer.println("<result>" + user.getFederatedIdentity()
					+ "</result>");
			writer.println("<result>" + user.getNickname() + "</result>");
			writer.println("<result>" + user.getUserId() + "</result>");
		} else {
			try {
				resp.sendError(400, "getCurrentUser call failed");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void getAuthDomain(CloudUser user2, PrintWriter writer,
			HttpServletRequest req, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);

		String authDomain = user.getAuthDomain();
		if (authDomain != null) {
			writer.println("<result>" + authDomain + "</result>");
		} else {
			try {
				resp.sendError(300, "getAuthDomain call failed");
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void createNewUser(CloudUser user2, PrintWriter writer,
			HttpServletRequest req, HttpServletResponse resp) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		String[] parms = req.getParameterValues(createNewUserCall);
		if (parms.length == 2) {
			log.info("with 2 parms");
			String email = parms[0];
			String authDomain = parms[1];
			user = user.createNewUser(email, authDomain);
			if (user == null) {
				log.severe("Unable to create a new User based on email,domain: "
						+ email + "," + authDomain);
				try {
					resp.sendError(300,
							"Unable to create a new User based on email,domain: "
									+ email + "," + authDomain);
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else {
				writer.println("<result>" + user.getAuthDomain() + "</result>");
				writer.println("<result>" + user.getEmail() + "</result>");
				writer.println("<result>" + user.getFederatedIdentity()
						+ "</result>");
				writer.println("<result>" + user.getNickname() + "</result>");
				writer.println("<result>" + user.getUserId() + "</result>");
			}
		} else if (parms.length == 3) {
			log.info("with 3 parms");
			String email = parms[0];
			String authDomain = parms[1];
			String userId = parms[2];
			user = user.createNewUser(email, authDomain, userId);
			if (user == null) {
				log.severe("Unable to create a new User based on email,authDomain,userId: "
						+ email + "," + authDomain + "," + userId);
				try {
					resp.sendError(400,
							"Unable to create a new User based on email,authDomain,userId: "
									+ email + "," + authDomain + "," + userId);
				} catch (IOException e) {
					e.printStackTrace();
				}
			} else {
				writer.println("<result>" + user.getAuthDomain() + "</result>");
				writer.println("<result>" + user.getEmail() + "</result>");
				writer.println("<result>" + user.getFederatedIdentity()
						+ "</result>");
				writer.println("<result>" + user.getNickname() + "</result>");
				writer.println("<result>" + user.getUserId() + "</result>");
			}
		}
	}

	private void handleNullOperation(PrintWriter writer, HttpServletRequest req) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		log.warning("operation is null");
		writer.println("<result>No operation found while calling "
				+ req.getServerName() + "servlet</result>");
	}

	private void handleEmptyOperation(PrintWriter writer, HttpServletRequest req) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		log.warning("operation is empty");
		writer.println("<result>Must pass an operation in calling "
				+ req.getServerName() + "servlet</result>");
	}

	private void compareTo(PrintWriter writer) {
		sourceMethod = Thread.currentThread().getStackTrace()[1].getMethodName().toString();
		log.info("Executing: " + sourceClass + "." + sourceMethod);
		CloudUser newUserObj = new CloudUser();
		int result = user.compareTo(newUserObj);
		writer.println("<result>" + Integer.toString(result) + "</result>");
	}

	enum CloudMethods {
		compareToMethod, createLoginURLMethod, createLogoutURLMethod, createNewUserMethod, getAuthDomainMethod, getCurrentUserMethod, getEmailMethod, getFederatedIdentityMethod, getNicknameMethod, getUserIdMethod, isUserAdminMethod, isUserLoggedInMethod
	};

	public static final String compareToCall = "compareTo";
	public static final String createLoginURLCall = "createLoginURL";
	public static final String createLogoutURLCall = "createLogoutURL";
	public static final String createNewUserCall = "createNewUser";
	public static final String getAuthDomainCall = "getAuthDomain";
	public static final String getCurrentUserCall = "getCurrentUser";
	public static final String getEmailCall = "getEmaill";
	public static final String getFederatedIdentityCall = "getFederatedIdentity";
	public static final String getNicknameCall = "getNickname";
	public static final String getUserIdCall = "getUserId";
	public static final String isUserAdminCall = "isUserAdmin";
	public static final String isUserLoggedInCall = "isUserLoggedIn";

}
